//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <ddk.h>
#include "tserial.h"

//////////////////////////////////////////////////////////////////////////////
EXTERN IDeviceDriver * CDECL CreateTSerial(uint_t uDeviceNo, void *pvParameter)
{
    TSerialDriver *pTSerialDriver = new TSerialDriver;
    if (NULL == pTSerialDriver) {
        kprintf("Error:There have no enough memory, %s, %d\n",
            __FILE__, __LINE__);
        return NULL;
    }
    pTSerialDriver->m_uIoBase = *(UInt16 *)pvParameter;

    pTSerialDriver->InitHardware();

    pTSerialDriver->AddRef();

    return pTSerialDriver;
}

void CDECL TSerialIsr(irq_t irq, void *pvDevice, InterruptContext *pContext)
{
    TSerialDriver *pTSerialDriver = (TSerialDriver *)pvDevice;
    UART_READ_INT_STAT(pTSerialDriver->m_uIoBase);
}

ECode TSerialDriver::Read(
    /* [in] */ UInt64 u64Offset,
    /* [in] */ UInt32 bytesToRead,
    /* [out] */ EzByteBuf buffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{

    return E_NOT_IMPLEMENTED;
}

ECode TSerialDriver::Write(
    /* [in] */ UInt64 u64Offset,
    /* [in] */ EzByteBuf buffer,
    /* [out] */ UInt32 * pBytesWritten,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    return E_NOT_IMPLEMENTED;
}

ECode TSerialDriver::Control(
    /* [in] */ Handle32 nControlCode,
    /* [in] */ EzByteBuf inBuffer,
    /* [out] */ EzByteBuf * pOutBuffer,
    /* [out] */ IEvent * * ppCompletionEvent)
{
    switch (nControlCode) {
        case 0 :{
            UART_DISABLE_INTS(m_uIoBase);
            break;
        }
        case 1 :{
//            Outb(_IER(m_uIoBase), _ETXEINT);
            kprintf("Serail send a char is '#'.\n");
            Outb(m_uIoBase, '#');
            break;
        }
        case 2 :{
//            Outb(_IER(m_uIoBase), _ERXINT | _ELSINT | _ETXEINT);
            break;
        }
    }

    return NOERROR;
}

ECode TSerialDriver::InitHardware()
{
    ECode ec = UART_SET_PARAMS(m_uIoBase, SerialBaudRate_115200,
                    SerialParity_Default, SerialStopBits_Default,
                    SerialByteSize_Default);

    if (FAILED(ec)) {
        kprintf("Failed to InitHardware, ec = 0x%08x\n", ec);
    }

    Outb(_IER(m_uIoBase), _ETXEINT);

    uint8_t uIrq = 0x04;
    switch (m_uIoBase) {
        case 0x3F8 :
        case 0x3E8 :uIrq = 0x04 ; break;
        case 0x2F8 :
        case 0x2E8 :uIrq = 0x03 ; break;
    }

    DzRegisterIsr(uIrq, IPL1, &TSerialIsr, this);
    DzUnregisterIsr(uIrq);

    return NOERROR;
}
